/*
 * @Author: 码农 2646995216@qq.com
 * @Date: 2025-03-07 14:36:13
 * @LastEditors: 码农 2646995216@qq.com
 * @LastEditTime: 2025-03-07 21:37:55
 * @FilePath: /pthread/RoundQueue/RoundQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include<iostream>
#include<string>
#include<vector>
#include<pthread.h>
#include<semaphore.h>

using namespace std;

template<class T>
class RoundQwueue
{
private:
    //信号量--
	void P(sem_t& sub)
	{
		sem_wait(&sub);
	}
    //信号量++
	void V(sem_t& add)
	{
		sem_post(&add);
	}
    //加锁
	void Lock(pthread_mutex_t& mutex)
	{
		pthread_mutex_lock(&mutex);
	}
    //解锁
	void Unlock(pthread_mutex_t& mutex)
	{
		pthread_mutex_unlock(&mutex);
	}
public:
    //初始化
	RoundQwueue(int max=20)
	:_q(max),_max(max),_con(0),_pro(0)
	{
		pthread_mutex_init(&_mutex1,nullptr);
		pthread_mutex_init(&_mutex2,nullptr);
        
		sem_init(&_sem1,0,max);
		sem_init(&_sem2,0,0);
	}
   
	//生产者生产数据
	void push(T& data)
	{
		P(_sem1);           //生产者的信号量--，也就是可放数据的空间减一
		Lock(_mutex1);

		_q[_pro++]=data;      //将数据添加到队列中
		//_pro++;

        _pro%=_q.size();    //保证队列的循环，使_pro的下标不会超过队列的最大空间值

		Unlock(_mutex1);
		V(_sem2);           //消费者的信号量++，也就是可拿数据的空间加一
	}
    
	//消费者拿数据
	void pop(T& data)
	{
		P(_sem2);           //消费者的信号量--，也就是可拿数据的空间减一
		Lock(_mutex2);

		data=_q[_con];      //将队列中的数据往外拿
		_con++;
		_con%=_q.size();    //保证队列的循环，使_con的下标不会超过队列的最大空间值

		Unlock(_mutex2);
		V(_sem1);           //生产者的信号量++，也就是可放数据的空间加一
	}
    
	//回收
	~RoundQwueue()
	{
		pthread_mutex_destroy(&_mutex1);
		pthread_mutex_destroy(&_mutex2);

		sem_destroy(&_sem1);
		sem_destroy(&_sem2);
	}

private:
	vector<T> _q;              //这个一定要初始化
	int _max;                  //队列空间的最大值
	int _con;                  //消费者的下标
	int _pro;                  //生产者的下标

	pthread_mutex_t _mutex1;   //生产者的锁
	pthread_mutex_t _mutex2;   //消费者的锁

	sem_t _sem1;               //生产者信号量，一开始为队列的最大值
	sem_t _sem2;               //消费者信号量，一开始为0
};
